#include "LocalScene.h"
#include "Utils/LogUtil.h"
#include "LocalEntity.h"
#include "Utils/StringUtil.h"
#include "Game/Component/Model.h"
#include "Render/RenderState.h"
#include "Render/Imgui/imgui.h"
#include "Math/Random.h"
#include "Game/GameState.h"
#include "Game/Component/MultiModel.h"
#include "PreRenderProcess.h"
#include "TaaProcess.h"

void LocalScene::OnInit()
{
	mCamera.SetSpeed(4.f);

	mPreRenderProcess = GetProcess<PreRenderProcess>("PreRenderProcess");
	mTaaProcess = GetProcess<TaaProcess>("TaaProcess");

	mCoordinateProcess = GetProcess<CoordinateProcess>("CoordinateProcess");



	GeometryGenerator geometryGenerator;
	GeometryGenerator::MeshData cubeData = geometryGenerator.CreateCube(1.2f, 1.2f, 1.2f, 1);
	GeometryGenerator::MeshData panelData = geometryGenerator.CreatePanel(6.f, 6.f, glm::vec3(0.f, 1.f, 0.f));


	mCubeEntity = CreateEntity<LocalEntity>("cube");

	// mCubeEntity->AddComponent<Model>(cubeData, true);

	mCubeEntity->AddComponent<Model>("Chair.obj");
	mCubeEntity->GetTransform().SetLocalScale(glm::vec3(3.f));

	// mCubeEntity->GetTransform().SetLocalPosition(glm::vec3(0.f, 0.7f, 0.f));
	mCubeEntity->GetTransform().UpdateMatrices();

	mCubeTransform = mCubeEntity->GetTransform().GetWorldMatrix();

	mCubeEntity->mAlbedoPath = "Pbr\\Wood_Albedo.png";
	mCubeEntity->mNormalPath = "Pbr\\Wood_Normal.png";
	mCubeEntity->mMetallicPath = "Pbr\\Wood_Metallic.png";
	mCubeEntity->mRoughnessPath = "Pbr\\Wood_Roughness.png";

	mCubeEntity->mHasNormal = true;



	mFloorEntity = CreateEntity<LocalEntity>("floor");
	mFloorEntity->AddComponent<Model>(panelData, true);

	mFloorEntity->mAlbedoPath = "Pbr\\Metal_Albedo.png";
	mFloorEntity->mNormalPath = "Pbr\\Metal_Normal.png";
	mFloorEntity->mMetallicPath = "Pbr\\Metal_Metallic.png";
	mFloorEntity->mRoughnessPath = "Pbr\\Metal_Roughness.png";

	mFloorEntity->mHasNormal = false;



	mLightRadius = 2.5f;
	mLightIntensity = 10.f;
	mLightColor = glm::vec3(1.f);
	mLightPosition = glm::vec3(2.5f, 2.f, -6.f);

#if 0
	for (uint32 i = 0; i < HALTON_SAMPLES; i++)
		mJitterSamples.push_back(glm::vec2((2.0f * HaltonSequence(2, i) - 1.0f), (2.0f * HaltonSequence(3, i) - 1.0f)));
#else
	mJitterSamples = {
		glm::vec2(0.0f, -1.0f / 3.0f),
		glm::vec2(-1.0f / 2.0f, 1.0f / 3.0f),
		glm::vec2(1.0f / 2.0f, -7.0f / 9.0f),
		glm::vec2(-3.0f / 4.0f, -1.0f / 9.0f),
		glm::vec2(1.0f / 4.0f, 5.0f / 9.0f),
		glm::vec2(-1.0f / 4.0f, -5.0f / 9.0f),
		glm::vec2(3.0f / 4.0f, 1.0f / 9.0f),
		glm::vec2(-7.0f / 8.0f, 7.0f / 9.0f)
	};
#endif

	mCubeEntity->mCurrModel = mCubeEntity->GetTransform().GetWorldMatrix();
	mCubeEntity->mPrevModel = mCubeEntity->mCurrModel;
	mFloorEntity->mCurrModel = mFloorEntity->GetTransform().GetWorldMatrix();
	mFloorEntity->mPrevModel = mFloorEntity->mCurrModel;

	mDeltaWidth = 1.f / float(GRenderState->GetWidth());
	mDeltaHeight = 1.f / float(GRenderState->GetHeight());

	uint32 jitterIndex = GGameState->GetFrameAmount() % HALTON_SAMPLES;
	glm::vec2 halton = mJitterSamples[jitterIndex];
	glm::vec2 jitter = glm::vec2(halton.x * mDeltaWidth, halton.y * mDeltaHeight);

	mBaseProj = mCamera.GetProj();

	mCurrProj = mBaseProj;
	mCurrProj[2][0] += jitter.x;
	mCurrProj[2][1] += jitter.y;

	mPrevProj = mBaseProj;
	mPrevProj[2][0] += jitter.x;
	mPrevProj[2][1] += jitter.y;

	mCurrView = mCamera.GetView();
	mPrevProj = mCurrView;
}

void LocalScene::OnTick(float deltaTime)
{
	mCubeEntity->GetTransform().SetLocalTransform(mCubeTransform);


	mCubeEntity->mPrevModel = mCubeEntity->mCurrModel;
	mCubeEntity->mCurrModel = mCubeEntity->GetTransform().GetWorldMatrix();
	mFloorEntity->mPrevModel = mFloorEntity->mCurrModel;
	mFloorEntity->mCurrModel = mFloorEntity->GetTransform().GetWorldMatrix();


	uint32 jitterIndex = GGameState->GetFrameAmount() % HALTON_SAMPLES;
	glm::vec2 halton = mJitterSamples[jitterIndex];
	glm::vec2 jitter = glm::vec2(halton.x * mDeltaWidth, halton.y * mDeltaHeight);

	mPrevProj = mCurrProj;

	mBaseProj = mCamera.GetProj();
	mCurrProj = mBaseProj;
	mCurrProj[2][0] += jitter.x;
	mCurrProj[2][1] += jitter.y;

	mPrevView = mCurrView;
	mCurrView = mCamera.GetView();
}

void LocalScene::OnResize()
{
	mDeltaWidth = 1.f / GRenderState->GetWidth();
	mDeltaHeight = 1.f / GRenderState->GetHeight();

	GameScene::OnResize();
}

float LocalScene::HaltonSequence(int base, int index)
{
	float result = 0;
	float f = 1;
	while (index > 0)
	{
		f /= base;
		result += f * (index % base);
		index = glm::floor(index / base);
	}

	return result;
}

void LocalScene::OnImgui()
{
	if (ImGui::BeginMainMenuBar())
	{
		ImGui::Text("Fps : %d ", GRenderState->GetFps());

		ImGui::RadioButton("NoTAA", &mTaaProcess->mDebugIndex, 0);
		ImGui::RadioButton("SimpleTAA", &mTaaProcess->mDebugIndex, 1);
		ImGui::RadioButton("ClampTAA", &mTaaProcess->mDebugIndex, 2);
		// ImGui::RadioButton("RayClipTAA", &mTaaProcess->mDebugIndex, 3);
		ImGui::RadioButton("VarianceClipTAA", &mTaaProcess->mDebugIndex, 3);
		ImGui::RadioButton("Velocity", &mTaaProcess->mDebugIndex, 4);

		ImGui::EndMainMenuBar();
	}

	ImGui::ColorEdit3("Color", &mLightColor.x);
	ImGui::InputFloat("Intensity", &mLightIntensity);
	ImGui::SliderFloat("Radius", &mLightRadius, 0.0f, 10.0f);


	ImGuizmo::BeginFrame();
	ImGuizmo::SetOrthographic(false);


	glm::vec3 cubePosition;
	glm::vec3 cubeRotation;
	glm::vec3 cubeScale;
	ImGuizmo::DecomposeMatrixToComponents(&mCubeTransform[0][0], &cubePosition.x, &cubeRotation.x, &cubeScale.x);
	ImGuizmo::RecomposeMatrixFromComponents(&cubePosition.x, &cubeRotation.x, &cubeScale.x, &mCubeTransform[0][0]);

	ImGuizmo::SetRect(0, 0, GRenderState->GetWidth(), GRenderState->GetHeight());
	ImGuizmo::Manipulate(&mCamera.mZmoView[0][0], &mCamera.mProj[0][0], ImGuizmo::TRANSLATE, ImGuizmo::WORLD, &mCubeTransform[0][0], NULL, NULL);
}

void LocalScene::OnExit()
{

}